﻿#include "DlgSelector.h"
#include "ui_DlgSelector.h"
#include <QPainter>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QHBoxLayout>

DlgSelector::DlgSelector(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DlgSelector)
{
    ui->setupUi(this);
    this->setWindowFlags(Qt::Popup|Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Dialog);
}

DlgSelector::~DlgSelector()
{
    delete ui;
}

void DlgSelector::SetTime(QDateTime dateTime)
{
    ui->widget->setDateTime(dateTime.date().year(),dateTime.date().month(),dateTime.date().day());
}

void DlgSelector::SetTitle(QString strTitle)
{
    ui->lableTitle->setText(strTitle);
}

//void DlgSelector::paintEvent(QPaintEvent *)
//{
//    QPainter painter(this);
//    painter.fillRect(this->rect(), QColor(169,169,169,220));
//}

void DlgSelector::on_btnCancel_clicked()
{
    this->close();
}

void DlgSelector::on_btnOk_clicked()
{
    QDateTime dateTime;
    QDate date;
    date.setDate(ui->widget->getYear(), ui->widget->getMonth(), ui->widget->getDay());
    dateTime.setDate(date);

    emit sigClickedOk(dateTime);

    this->close();
}

/****************************************************************************************************************
 *
 *  时间选择器基础组合
 *
 *****************************************************************************************************************/
SelectorDateTime::SelectorDateTime(QWidget *parent) : QWidget(parent)
{
    //年份选择器
    tumblerYear = new Selector(this);
    QStringList listYear;
    for (int i = 2019; i <= 2035; i++) {
        listYear << QString("%1 年").arg(i);
    }
    tumblerYear->setListValue(listYear);
    //月份选择器
    tumblerMonth = new Selector(this);
    QStringList listMonth;
    for (int i = 1; i <= 12; i++) {
        listMonth << QString("%1 月").arg(i);
    }
    tumblerMonth->setListValue(listMonth);
    //日期选择器
    tumblerDay = new Selector(this);
    QStringList listDay;
    for (int i = 1; i <= 31; i++) {
        listDay << QString("%1 日").arg(i);
    }
    tumblerDay->setListValue(listDay);
    //年月日联动
    connect(tumblerYear, SIGNAL(currentValueChanged(QString)), this, SLOT(currentValueChanged(QString)));
    connect(tumblerMonth, SIGNAL(currentValueChanged(QString)), this, SLOT(currentValueChanged(QString)));
    tumblerYear->setTextColor(QColor(255, 255, 255));
    tumblerMonth->setTextColor(QColor(255, 255, 255));
    tumblerDay->setTextColor(QColor(255, 255, 255));
    //将选择器添加到布局
    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->setMargin(0);
    layout->setSpacing(0);
    layout->addWidget(tumblerYear);
    layout->addWidget(tumblerMonth);
    layout->addWidget(tumblerDay);
}

void SelectorDateTime::currentValueChanged(const QString &)
{
    int month = tumblerMonth->getCurrentValue().left(2).toInt();
    //记住之前的日期
    int day = tumblerDay->getCurrentValue().left(2).toInt();
    //计算该月最大日期
    int maxDay = 30;
    if (month == 2) {
        //平年28天 闰年29天
        int year = tumblerYear->getCurrentValue().left(4).toInt();
        bool isLoopYear = (((0 == (year % 4)) && (0 != (year % 100))) || (0 == (year % 400)));
        if (isLoopYear) {
            maxDay = 29;
        } else {
            maxDay = 28;
        }
    } else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
        maxDay = 31;
    }
    QStringList listDay;
    for (int i = 1; i <= maxDay; i++) {
        listDay << QString("%1 日").arg(i);
    }
    tumblerDay->setListValue(listDay);
    //如果上次的日期大于最大的日期则设置为最大的日期
    if (day > maxDay) {
        tumblerDay->setCurrentIndex(maxDay - 1);
    } else {
        tumblerDay->setCurrentIndex(day - 1);
    }
}

int SelectorDateTime::getYear() const
{
    return tumblerYear->getCurrentValue().left(4).toInt();
}

int SelectorDateTime::getMonth() const
{
    return tumblerMonth->getCurrentValue().left(2).toInt();
}

int SelectorDateTime::getDay() const
{
    return tumblerDay->getCurrentValue().left(2).toInt();
}

void SelectorDateTime::setYear(int year)
{
    tumblerYear->setCurrentValue(QString("%1 年").arg(year));
}

void SelectorDateTime::setMonth(int month)
{
    tumblerMonth->setCurrentValue(QString("%1 月").arg(month));
}

void SelectorDateTime::setDay(int day)
{
    tumblerDay->setCurrentValue(QString("%1 日").arg(day));
}

void SelectorDateTime::setDateTime(int year, int month, int day)
{
    setYear(year);
    setMonth(month);
    setDay(day);
}

/****************************************************************************************************************
 *
 *  时间选择器基础
 *
 *****************************************************************************************************************/
Selector::Selector(QWidget *parent) : QWidget(parent)
{
    currentIndex = 0;
    currentValue = "1";

    for (int i = 1; i <= 12; i++) {
        listValue.append(QString::number(i));
    }

    foreground = QColor(0, 0, 0);
    background = QColor(49, 49, 49, 200);
    lineColor = QColor(0, 140, 252, 255);
    textColor = QColor(255, 255, 255);

    horizontal = false;

    percent = 3;
    offset = 0;
    pressed = 0;
    pressedPos = 0;
    currentPos = 0;

    setFont(QFont("Arial", 8));
}

void Selector::wheelEvent(QWheelEvent *e)
{
    //滚动的角度,*8就是鼠标滚动的距离
    int degrees = e->delta() / 8;
    //滚动的步数,*15就是鼠标滚动的角度
    int steps = degrees / 15;
    //如果是正数代表为左边移动,负数代表为右边移动
    if (e->orientation() == Qt::Vertical) {
        int index = currentIndex - steps;
        if (steps > 0) {
            if (index > 0) {
                setCurrentIndex(index);
            } else {
                setCurrentIndex(0);
            }
        } else {
            if (index < listValue.count() - 1) {
                setCurrentIndex(index);
            } else {
                setCurrentIndex(listValue.count() - 1);
            }
        }
    }
}

void Selector::mousePressEvent(QMouseEvent *e)
{
    pressed = true;
    int target = e->pos().x();
    if (!horizontal) {
        target = e->pos().y();
    }
    pressedPos = target;
}

void Selector::mouseMoveEvent(QMouseEvent *e)
{
    int count = listValue.count();
    if (count <= 1) {
        return;
    }
    int pos = e->pos().x();
    int target = this->width();
    if (!horizontal) {
        pos = e->pos().y();
        target = this->height();
    }
    int index = listValue.indexOf(currentValue);
    if (pressed) {
        //数值到边界时,阻止继续往对应方向移动
        if ((index == 0 && pos >= pressedPos) || (index == count - 1 && pos <= pressedPos)) {
            return;
        }
        offset = pos - pressedPos;
        //若移动速度过快时进行限制
        if (offset > target / percent) {
            offset = target / percent;
        } else if (offset < -target / percent) {
            offset = -target / percent;
        }
        static int oldIndex = -1;
        if (oldIndex != index) {
            emit currentIndexChanged(index);
            emit currentValueChanged(listValue.at(index));
            oldIndex = index;
        }
        update();
    }
}

void Selector::mouseReleaseEvent(QMouseEvent *)
{
    if (pressed) {
        pressed = false;
        //矫正到居中位置
        checkPosition();
    }
}

void Selector::paintEvent(QPaintEvent *)
{
    //绘制准备工作,启用反锯齿
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    int count = listValue.count();
    if (count <= 1) {
        return;
    }
    int target = this->width();
    if (!horizontal) {
        target = this->height();
    }
    int index = listValue.indexOf(currentValue);
    //当右移偏移量大于比例且当前值不是第一个则索引-1
    if (offset >= target / percent && index > 0) {
        pressedPos += target / percent;
        offset -= target / percent;
        index -= 1;
    }
    //当左移偏移量小于比例且当前值不是末一个则索引+1
    if (offset <= -target / percent && index < count - 1) {
        pressedPos -= target / percent;
        offset += target / percent;
        index += 1;
    }
    currentIndex = index;
    currentValue = listValue.at(index);
    //绘制背景
    drawBg(&painter);
    //绘制线条
    drawLine(&painter);
    //绘制中间值
    painter.setPen(textColor);
    drawText(&painter, index, offset);
    painter.setPen(foreground);
    //绘制左侧值
    if (index != 0) {
        drawText(&painter, index - 1, offset - target / percent);
    }
    //绘制右侧值
    if (index != count - 1) {
        drawText(&painter, index + 1, offset + target / percent);
    }
}

void Selector::drawBg(QPainter *painter)
{
    painter->save();
    painter->setPen(Qt::NoPen);
    painter->setBrush(background);
    painter->drawRect(rect());
    painter->restore();
}

void Selector::drawLine(QPainter *painter)
{
    //上下部分偏移量
    int offset = 10;
    int width = this->width();
    int height = this->height();
    painter->save();
    painter->setBrush(Qt::NoBrush);
    QPen pen;
    pen.setWidth(3);
    pen.setColor(lineColor);
    pen.setCapStyle(Qt::RoundCap);
    painter->setPen(pen);

    //每次同时存在三个元素
    if (horizontal) {
        painter->drawLine(width / 3 * 1, offset, width / 3 * 1, height - offset);
        painter->drawLine(width / 3 * 2, offset, width / 3 * 2, height - offset);
    } else {
        painter->drawLine(offset, height / 3 * 1, width - offset,  height / 3 * 1);
        painter->drawLine(offset, height / 3 * 2, width - offset,  height / 3 * 2);
    }
    painter->restore();
}

void Selector::drawText(QPainter *painter, int index, int offset)
{
    painter->save();
    int width = this->width();
    int height = this->height();
    QString strValue = listValue.at(index);
    int target = width;
    if (!horizontal) {
        target = height;
    }
    QFont font = painter->font();
    font.setPixelSize((target - qAbs(offset)) / 8);
    painter->setFont(font);
    if (horizontal) {
        int textWidth = painter->fontMetrics().width(strValue);
        int initX = width / 2 + offset - textWidth / 2;
        painter->drawText(QRect(initX, 0, textWidth, height), Qt::AlignCenter, strValue);

        //计算最后中间值停留的起始坐标,以便鼠标松开时矫正居中
        if (index == currentIndex) {
            currentPos = initX;
        }
    } else {
        int textHeight = painter->fontMetrics().height();
        int initY = height / 2 + offset - textHeight / 2;
        painter->drawText(QRect(0, initY, width, textHeight), Qt::AlignCenter, strValue);

        //计算最后中间值停留的起始坐标,以便鼠标松开时矫正居中
        if (index == currentIndex) {
            currentPos = initY;
        }
    }
    painter->restore();
}

void Selector::checkPosition()
{
    int target = this->width();
    if (!horizontal) {
        target = this->height();
    }
    //左右滑动样式,往左滑动时,offset为负数,当前值所在X轴坐标小于宽度的一半,则将当前值设置为下一个值
    //左右滑动样式,往右滑动时,offset为正数,当前值所在X轴坐标大于宽度的一半,则将当前值设置为上一个值
    //上下滑动样式,往上滑动时,offset为负数,当前值所在Y轴坐标小于高度的一半,则将当前值设置为下一个值
    //上下滑动样式,往下滑动时,offset为正数,当前值所在Y轴坐标大于高度的一半,则将当前值设置为上一个值
    if (offset < 0) {
        if (currentPos < target / 2) {
            offset = 0;
            setCurrentIndex(currentIndex + 1);
        }
    } else {
        if (currentPos > target / 2) {
            offset = 0;
            setCurrentIndex(currentIndex - 1);
        }
    }
}

QStringList Selector::getListValue() const
{
    return this->listValue;
}

int Selector::getCurrentIndex() const
{
    return this->currentIndex;
}

QString Selector::getCurrentValue() const
{
    return this->currentValue;
}

bool Selector::getHorizontal() const
{
    return this->horizontal;
}

QColor Selector::getForeground() const
{
    return this->foreground;
}

QColor Selector::getBackground() const
{
    return this->background;
}

QColor Selector::getLineColor() const
{
    return this->lineColor;
}

QColor Selector::getTextColor() const
{
    return this->textColor;
}

QSize Selector::sizeHint() const
{
    return QSize(50, 150);
}

QSize Selector::minimumSizeHint() const
{
    return QSize(10, 10);
}

void Selector::setListValue(const QStringList &listValue)
{
    if (listValue.count() > 0) {
        this->listValue = listValue;
        setCurrentIndex(0);
        setCurrentValue(listValue.at(0));
        update();
    }
}

void Selector::setCurrentIndex(int currentIndex)
{
    if (currentIndex >= 0) {
        this->currentIndex = currentIndex;
        this->currentValue = listValue.at(currentIndex);
        emit currentIndexChanged(this->currentIndex);
        emit currentValueChanged(this->currentValue);
        update();
    }
}

void Selector::setCurrentValue(const QString &currentValue)
{
    if (listValue.contains(currentValue)) {
        this->currentValue = currentValue;
        this->currentIndex = listValue.indexOf(currentValue);
        emit currentIndexChanged(this->currentIndex);
        emit currentValueChanged(this->currentValue);
        update();
    }
}

void Selector::setHorizontal(bool horizontal)
{
    if (this->horizontal != horizontal) {
        this->horizontal = horizontal;
        update();
    }
}

void Selector::setForeground(const QColor &foreground)
{
    if (this->foreground != foreground) {
        this->foreground = foreground;
        update();
    }
}

void Selector::setBackground(const QColor &background)
{
    if (this->background != background) {
        this->background = background;
        update();
    }
}

void Selector::setLineColor(const QColor &lineColor)
{
    if (this->lineColor != lineColor) {
        this->lineColor = lineColor;
        update();
    }
}

void Selector::setTextColor(const QColor &textColor)
{
    if (this->textColor != textColor) {
        this->textColor = textColor;
        update();
    }
}
